<template>
  <div class="block">
    <input
      type="text"
      @keydown="changeMoveWay"
      ref="inputDom"
      @blur="focus"
      style="opacity: 0; position: absolute"
    />
    <score-pane :rowNum="rowNum" :score="scoreNum"></score-pane>
    <div class="startGame">
      <button class="snack-startgame" @click="initMove" :disabled="ifStart">
        开始游戏
      </button>
      <button class="snack-startgame" @click="resetMove" :disabled="!ifStart">
        重来
      </button>
      <button class="snack-startgame" @click="goBack">返回</button>
    </div>
    <div class="block-body" ref="bodyDom">
      <div
        class="block-body-item"
        v-for="(item, index) in totalArr"
        :key="index"
        :style="{
          backgroundColor:
            currentNum.includes(index) || totalNum.includes(index)
              ? 'rgba(0,0,0,0.6)'
              : 'rgba(255,255,255,0.6)',
        }"
      ></div>
    </div>
  </div>
</template>

<script setup lang="ts">
import scorePane from "./scorePlan.vue";
import { onMounted, ref, Ref, onUnmounted, defineEmits } from "vue";
import changeUtil from "./changeUtil";
type TcurrentNumType = "one" | "two" | "three" | "four" | "five";
const totalArr = ref<Array<any>>([]);
const one = ref<Array<number>>([-11, -10, -9, -8]);
const two = ref<Array<number>>([-31, -30, -10, -9]);
const three = ref<Array<number>>([-29, -30, -10, -9]);
const four = ref<Array<number>>([-11, -10, -9, -29]);
const five = ref<Array<number>>([-11, -10, -9, -30]);
const totalNum = ref<Array<number>>([]);
const inputDom = ref<HTMLInputElement | null>(null);
const currentNum = ref<Array<number>>([]);
const bodyDom = ref<HTMLDivElement | null>(null);
const timer = ref<number | null>(null);
const downTime = ref<number>(500);
const currentNumType = ref<TcurrentNumType>("one");
const status = ref<number>(0);
const ifStart = ref<boolean>(false);
const scoreNum = ref<number>(0);
const rowNum = ref<number>(0);
onMounted(() => {
  totalArr.value.length = 440;
  totalArr.value.fill("");
  randomNum();
  inputDom.value!.focus();
});
const emit = defineEmits(["goBack"]);
const goBack = () => {
  emit("goBack");
};
onUnmounted(() => {
  if (timer.value) {
    clearTimeout(timer.value);
  }
});
const resetMove = () => {
  timer.value && clearInterval(timer.value);
  ifStart.value = false;
  totalNum.value = [];
  currentNum.value = [];
  (currentNumType.value = "one"), randomNum();
};
const initMove = () => {
  ifStart.value = true;
  startMove();
};
const startMove = () => {
  timer.value = setInterval(() => {
    moveDown();
  }, downTime.value);
};
const randomNum = () => {
  status.value = 0;
  const randomIndex = Math.floor(Math.random() * 5);
  const numArr: Array<{ type: TcurrentNumType; value: number[] }> = [
    { type: "one", value: one.value },
    { type: "two", value: two.value },
    { type: "three", value: three.value },
    { type: "four", value: four.value },
    { type: "five", value: five.value },
  ];
  currentNumType.value = numArr[randomIndex].type;
  currentNum.value = numArr[randomIndex].value;
};
const ifBestScore = () => {
  const bestRowNum: string = localStorage.getItem("blockBestRow") || "0";
  const bestScoreNum: string = localStorage.getItem("blockBestScore") || "0";
  rowNum.value > parseInt(bestRowNum) &&
    localStorage.setItem("blockBestRow", rowNum.value + "");
  scoreNum.value > parseInt(bestScoreNum) &&
    localStorage.setItem("blockBestScore", scoreNum.value + "");
};
const judgeSuccessIncrease = () => {
  //获取当前放空纵向的index
  const heightRow = currentNum.value.filter(
    (item) => !currentNum.value.includes(item + 1)
  );
  const allNum: Array<number[]> = [];
  heightRow.forEach((item) => {
    const min = Math.floor(item / 20) * 20;
    const max = min + 19;
    if (totalNum.value.filter((item) => item >= min && item <= max).length === 20) {
      allNum.push([min, max]);
    }
  });
  rowNum.value += allNum.length;
  scoreNum.value += Math.pow(allNum.length, 2);
  ifBestScore();
  if (allNum.length) {
    totalNum.value = totalNum.value.reduce((pre: Array<number>, currentValue: number) => {
      let temValue = currentValue;
      let needIn = false;
      if (temValue < allNum[0][0]) {
        needIn = true;
        temValue += 20 * allNum.length;
      } else if (temValue > allNum[allNum.length - 1][1]) {
        needIn = true;
      }
      if (needIn) {
        pre.push(temValue);
      }
      return pre;
    }, []);
  }
};
const moveDown = () => {
  if (stopMoveDown()) {
    // 当触底的时候进入
    if (currentNum.value.some((item) => item < 0)) {
      timer.value && clearInterval(timer.value);
      alert("失败");
    }
    totalNum.value = [...totalNum.value, ...currentNum.value];
    judgeSuccessIncrease();
    randomNum();
  }
  currentNum.value = currentNum.value.map((item) => item + 20);
};
const startChange = () => {
  changeUtil[currentNumType.value][status.value](
    currentNum.value,
    (afterChangeArr: number[], afterStatus: number) => {
      const afterMoveArr = changeEdgeJudge(afterChangeArr);
      currentNum.value !== afterMoveArr && (status.value = afterStatus);
      currentNum.value = afterMoveArr || afterChangeArr;
    }
  );
};
const rowsSize = (row1: number) => {
  return row1 % 20;
};
const changeEdgeJudge = (afterChangeArr: number[]) => {
  const afterChangeArrConfig = gameEdgeJudge(afterChangeArr);
  const num = afterChangeArrConfig.afterChangeArr.find((item) =>
    totalNum.value.includes(item)
  );
  if (afterChangeArrConfig.ifMove && num) {
    return currentNum.value;
  }
  if (!num) {
    return afterChangeArrConfig.afterChangeArr;
  }
  afterChangeArr = afterChangeArrConfig.afterChangeArr;
  if (rowsSize(num) < rowsSize(currentNum.value[0])) {
    // 右边
    return rightMoveUtilFix(afterChangeArr);
  } else if (rowsSize(num) > rowsSize(currentNum.value[0])) {
    return leftMoveUtilFix(afterChangeArr);
  }
  const judgeBottom = afterChangeArr.find((item) => item / 20 >= 21);
  if (judgeBottom) {
    return bottomMoveUtilFix(afterChangeArr);
  }
};

const gameEdgeJudge = (afterChangeArr: number[]) => {
  const location = rowsSize(currentNum.value[0]) > 10;
  afterChangeArr = bottomEdgeMoveUtilFix(afterChangeArr);
  return location
    ? leftEdgwMoveUtilFix(afterChangeArr)
    : rightEdgeMoveUtilFix(afterChangeArr);
};
const leftEdgwMoveUtilFix = (afterChangeArr: number[]) => {
  let ifMove = false;
  while (afterChangeArr.find((item) => rowsSize(item) < 1)) {
    afterChangeArr = afterChangeArr.map((item) => item - 1);
    ifMove = true;
  }
  return { afterChangeArr, ifMove };
};
const rightEdgeMoveUtilFix = (afterChangeArr: number[]) => {
  let ifMove = false;
  while (afterChangeArr.find((item) => rowsSize(item) > 15)) {
    afterChangeArr = afterChangeArr.map((item) => item + 1);
    ifMove = true;
  }
  return { afterChangeArr, ifMove };
};
const bottomEdgeMoveUtilFix = (afterChangeArr: number[]) => {
  while (afterChangeArr.find((item) => item >= 440 && item <= 450)) {
    afterChangeArr = afterChangeArr.map((item) => item - 20);
  }
  return afterChangeArr;
};
const leftMoveUtilFix = (afterChangeArr: number[]) => {
  let count = 0;
  while (afterChangeArr.find((item) => totalNum.value.includes(item)) && count <= 2) {
    count++;
    afterChangeArr = afterChangeArr.map((item) => item - 1);
  }
  return count === 3 ? currentNum.value : afterChangeArr;
};
const rightMoveUtilFix = (afterChangeArr: number[]) => {
  let count = 0;
  while (afterChangeArr.find((item) => totalNum.value.includes(item)) && count <= 2) {
    count++;
    afterChangeArr = afterChangeArr.map((item) => item + 1);
  }
  return count === 3 ? currentNum.value : afterChangeArr;
};
const bottomMoveUtilFix = (afterChangeArr: number[]) => {
  while (afterChangeArr.find((item) => totalNum.value.includes(item))) {
    afterChangeArr = afterChangeArr.map((item) => item - 20);
  }
  return afterChangeArr;
};
const stopMoveDown = () => {
  const ifInfinitEdge = currentNum.value.find((item) => 420 <= item && item <= 439);
  const testMoveDownNum = [...currentNum.value];
  const ifTouchEdge = testMoveDownNum
    .map((item) => item + 20)
    .find((item) => totalNum.value.includes(item));
  return ifInfinitEdge || ifTouchEdge;
};
const moveLeft = () => {
  const border = currentNum.value.find((item) => item % 20 === 0);
  const afterMoveBorder = currentNum.value.map((item) => item - 1);
  const afterBorder = afterMoveBorder.find((item) => totalNum.value.includes(item));
  if (border || afterBorder) return;
  currentNum.value = afterMoveBorder;
};
const moveRight = () => {
  const border = currentNum.value.find((item) => item % 20 === 19);
  const afterMoveBorder = currentNum.value.map((item) => item + 1);
  const afterBorder = afterMoveBorder.find((item) => totalNum.value.includes(item));
  if (border || afterBorder) return;
  currentNum.value = afterMoveBorder;
};
const changeMoveWay = (e: KeyboardEvent) => {
  const keyCodeMenu: {
    [key in number]: Function;
  } = {
    39: moveRight,
    37: moveLeft,
    40: moveDown,
    38: startChange,
  };
  keyCodeMenu[e.keyCode] && keyCodeMenu[e.keyCode]();
};
const focus = () => {
  inputDom.value && inputDom.value.focus();
};
</script>

<style lang="scss" scoped>
.block {
  position: relative;
  height: calc(100vh - 50px);
  .startGame {
    position: absolute;
    top: 5px;
    left: 0;
    right: 0;
    text-align: center;
    .snack-startgame {
      margin: 0 16px;
      width: 75px;
      height: 35px;
      background-color: #3478ec99;
      border: none;
      font-size: 13px;
      flex-wrap: bold;
      color: #333;
      border-radius: 5px;
      &:hover {
        background: #3478ec88;
      }
    }
  }
  &-body {
    position: absolute;
    display: flex;
    width: 580px;
    // height: 660px;
    flex-wrap: wrap;
    left: 0;
    right: 0;
    top: 50px;
    margin: auto;
    &-item {
      width: 29px;
      height: 29px;
      background-color: rgb(255, 255, 255, 0.7);
    }
  }
}
</style>
